package targz

import (
	"archive/tar"
	"compress/gzip"
	"io"
	"os"
	"path/filepath"
	"strings"

	"gitee.com/haodreams/golib/logs"
)

func encodeFile(tw *tar.Writer, path string) (err error) {
	fi, err := os.Stat(path)
	if err != nil {
		return
	}

	h, err := tar.FileInfoHeader(fi, "")
	if err != nil {
		return err
	}

	h.Name = filepath.Base(path)
	err = tw.WriteHeader(h)
	if err != nil {
		return err
	}
	fr, err := os.Open(h.Name)
	if err != nil {
		return err
	}

	_, err = io.Copy(tw, fr)
	if err != nil {
		fr.Close()
		return err
	}
	fr.Close()
	return
}

func encode(tw *tar.Writer, path string, appFile ...string) (err error) {
	fs, err := os.ReadDir(path)
	if err != nil {
		return err
	}
	for _, f := range fs {
		if f.Name() == "." || f.Name() == ".." {
			continue
		}

		fi, err := os.Stat(path + f.Name())
		if err != nil {
			continue
		}

		name := path + f.Name()
		h, err := tar.FileInfoHeader(fi, "")
		if err != nil {
			return err
		}

		h.Name = name
		err = tw.WriteHeader(h)
		if err != nil {
			return err
		}
		if f.IsDir() {
			//如果是目录，不继续执行
			encode(tw, name+"/", appFile...)
			continue
		}

		for _, app := range appFile {
			if strings.HasSuffix(f.Name(), app) {
				h.Mode |= 0111 //7x 可执行权限
			}
		}

		fr, err := os.Open(name)
		if err != nil {
			return err
		}

		_, err = io.Copy(tw, fr)
		if err != nil {
			fr.Close()
			return err
		}
		fr.Close()
	}
	return
}

//tar.gz 打包
/**
 * @description:
 * @param {*} src
 * @param {string} tarPath
 * @param {...string} appFile app 文件带有可执行权限
 * @return {*}
 */
func Encode(src, tarPath string, appFile ...string) (err error) {
	//创建tar 文件
	fw, err := os.Create(tarPath)
	if err != nil {
		return
	}
	defer fw.Close()

	//创建 gzip 流
	gw := gzip.NewWriter(fw)
	defer gw.Close()

	//创建 tar 流
	tw := tar.NewWriter(gw)
	defer tw.Close()

	if !strings.HasSuffix(src, "/") {
		src += "/"
	}
	err = encode(tw, src, appFile...)

	return err
}

//tar.gz 打包
/**
 * @description:
 * @param {*} src
 * @param {string} tarPath
 * @param {...string} appFile app 文件带有可执行权限
 * @return {*}
 */
func Encodes(tarPath string, srcs ...string) (err error) {
	//创建tar 文件
	fw, err := os.Create(tarPath)
	if err != nil {
		return
	}
	defer fw.Close()

	//创建 gzip 流
	gw := gzip.NewWriter(fw)
	defer gw.Close()

	//创建 tar 流
	tw := tar.NewWriter(gw)
	defer tw.Close()

	for _, src := range srcs {
		fi, err := os.Stat(src)
		if err != nil {
			continue
		}
		if fi.IsDir() {
			if !strings.HasSuffix(src, "/") {
				src += "/"
			}
			err = encode(tw, src)
		} else {
			err = encodeFile(tw, src)
		}
		if err != nil {
			return err
		}
	}

	return err
}

// tar.gz 解包
func Decode(tarfile, dir string) (err error) {
	if !(strings.HasSuffix(dir, "/") || strings.HasSuffix(dir, "\\")) {
		dir += "/"
	}
	//打开tar.gz 文件流
	fr, err := os.Open(tarfile)
	if err != nil {
		return
	}
	defer fr.Close()

	//打开gzip 流
	gr, err := gzip.NewReader(fr)
	if err != nil {
		return
	}
	defer gr.Close()

	tr := tar.NewReader(gr)
	for {
		hdr, err := tr.Next()
		if err != nil {
			if err == io.EOF {
				break
			} else {
				return err
			}
		}

		path := dir + hdr.Name
		fi := hdr.FileInfo()
		if fi.IsDir() {
			os.MkdirAll(path, fi.Mode())
		} else {
			dir := filepath.Dir(path)
			os.MkdirAll(dir, 0755)
			fw, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fi.Mode())
			if err != nil {
				logs.Warn(path, err)
				continue
			}
			//os.Chown(path, hdr.Uid, hdr.Gid)
			os.Chtimes(path, hdr.AccessTime, hdr.ModTime)
			_, err = io.Copy(fw, tr)
			if err != nil {
				logs.Warn(path, err)
				fw.Close()
				continue
			}
			fw.Close()
		}
	}
	return
}
